package com.forum.service.impl;

import com.forum.common.constant.PostConstants;
import com.forum.common.exception.BusinessException;
import com.forum.config.UploadConfig;
import com.forum.mapper.*;
import com.forum.model.dto.PostDTO;
import com.forum.model.entity.Post;
import com.forum.model.entity.PostAuditLog;
import com.forum.model.entity.PostTag;
import com.forum.model.entity.Tag;
import com.forum.model.vo.CategoryVO;
import com.forum.model.vo.PostVO;
import com.forum.model.vo.TagVO;
import com.forum.post.config.AutoAuditConfig;
import com.forum.post.dto.AuditResultDTO;
import com.forum.post.service.AutoAuditService;
import com.forum.service.PostService;
import com.forum.service.UserCacheService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import com.forum.common.event.MessageEventPublisher;
import com.forum.common.event.PostAuditEvent;

import java.io.File;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor
public class PostServiceImpl implements PostService {

    private final PostMapper postMapper;
    private final CategoryMapper categoryMapper;
    private final TagMapper tagMapper;
    private final PostTagMapper postTagMapper;
    private final UploadConfig uploadConfig;
    private final UserCacheService userCacheService;
    private final PostAuditLogMapper postAuditLogMapper;

    @Autowired
    private AutoAuditService autoAuditService;
    
    @Autowired
    private AutoAuditConfig auditConfig;
    
    @Autowired
    private MessageEventPublisher messageEventPublisher;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public PostVO createPost(PostDTO postDTO) {
        // 1. 验证用户ID
        if (postDTO.getUserId() == null) {
            throw new BusinessException("用户ID不能为空");
        }
        
        // 验证分类ID
        if (postDTO.getCategoryId() == null) {
            throw new BusinessException("分类ID不能为空");
        }

        // 2. 创建帖子
        Post post = new Post();
        BeanUtils.copyProperties(postDTO, post);
        post.setCreatedAt(LocalDateTime.now());
        post.setUpdatedAt(LocalDateTime.now());
        post.setViews(0);
        post.setLikes(0);
        post.setComments(0);
        post.setIsTop(false);
        post.setIsHot(false);
        
        // 始终将新帖子状态设置为待审核，忽略客户端传入的状态值
        post.setStatus(PostConstants.STATUS_PENDING); // 待审核状态
        
        // 3. 保存帖子
        postMapper.insert(post);
        
        // 4. 处理标签
        if (postDTO.getTags() != null && !postDTO.getTags().isEmpty()) {
            handleTags(post.getId(), postDTO.getTags());
        }
        
        // 5. 更新分类的帖子数量
        categoryMapper.incrementPostCount(post.getCategoryId());
        
        // 6. 调用自动审核服务
        if (auditConfig.isEnabled()) {
            try {
                AuditResultDTO auditResult = autoAuditService.auditPost(post);
                
                // 保存审核结果到帖子
                post.setAiAuditResult(auditResult.getAuditResult());
                post.setAiConfidence(auditResult.getConfidence());
                post.setAiSuggestion(auditResult.getSuggestion());
                
                // 自动审核流程
                handleAuditResult(post, auditResult);
                
                // 更新帖子状态
                postMapper.updateById(post);
                
                log.info("帖子 {} 自动审核结果: {}, 置信度: {}", 
                        post.getId(), auditResult.getAuditResult(), auditResult.getConfidence());
            } catch (Exception e) {
                log.error("自动审核失败，帖子将保持待审核状态: {}", e.getMessage(), e);
            }
        }
        
        // 7. 返回帖子视图对象
        return getPost(post.getId());
    }
    
    /**
     * 处理审核结果
     */
    private void handleAuditResult(Post post, AuditResultDTO auditResult) {
        log.info("处理审核结果: postId={}, result={}, confidence={}", 
                post.getId(), auditResult.getAuditResult(), auditResult.getConfidence());
        
        // 保存审核结果到数据库
        post.setAiAuditResult(auditResult.getAuditResult());
        post.setAiConfidence(auditResult.getConfidence());
        
        // 获取第一条理由作为建议，如果没有则使用默认建议
        String suggestion = auditResult.getSuggestion();
        if (suggestion == null || suggestion.isEmpty()) {
            if (auditResult.getReasons() != null && !auditResult.getReasons().isEmpty()) {
                suggestion = String.join("; ", auditResult.getReasons());
            } else {
                suggestion = "系统自动审核：" + ("PASS".equals(auditResult.getAuditResult()) ? "内容正常" : 
                            "REVIEW".equals(auditResult.getAuditResult()) ? "需要人工审核" : "内容不合规");
            }
        }
        post.setAiSuggestion(suggestion);
        
        // 更新数据库
//        postMapper.updateByIds(post);
        // 记录审核日志
        PostAuditLog auditLog = new PostAuditLog();
        auditLog.setPostId(post.getId());
        auditLog.setAuditorId(2L);

        // 设置帖子状态
        if ("PASS".equals(auditResult.getAuditResult()) && 
                auditResult.getConfidence() >= auditConfig.getAutoApproveThreshold()) {
            // 自动通过
            post.setStatus(PostConstants.STATUS_PUBLISHED);
            postMapper.updateByIds(post);
            // 记录审核日志
            auditLog.setAction("approve");
            auditLog.setCreatedAt(LocalDateTime.now());
            postAuditLogMapper.insert(auditLog);

            log.info("帖子审核通过: {}, 审核人: {}", post.getId(), "AI");
            // 发送审核通过通知
            try {
                // 假设系统管理员ID为1L，可以根据实际情况调整
                Long systemAdminId = 1L;
                messageEventPublisher.publishPostAuditEvent(
                    PostAuditEvent.approved(systemAdminId, post.getUserId(), post.getId(), 
                        post.getTitle(), suggestion)
                );
                log.info("发送审核通过通知成功: postId={}", post.getId());
            } catch (Exception e) {
                log.error("发送审核通过通知失败: {}", e.getMessage(), e);
            }
        } else if ("REJECT".equals(auditResult.getAuditResult()) && 
                auditResult.getConfidence() >= auditConfig.getAutoRejectThreshold()) {
            // 自动拒绝
            post.setStatus(PostConstants.STATUS_REJECTED);
            postMapper.updateByIds(post);
            // 记录审核日志
            auditLog.setAction("reject");
            auditLog.setRemark(suggestion);
            auditLog.setCreatedAt(LocalDateTime.now());
            postAuditLogMapper.insert(auditLog);
            // 发送审核拒绝通知
            try {
                // 假设系统管理员ID为1L，可以根据实际情况调整
                Long systemAdminId = 1L;
                messageEventPublisher.publishPostAuditEvent(
                    PostAuditEvent.rejected(systemAdminId, post.getUserId(), post.getId(), 
                        post.getTitle(), suggestion)
                );
                log.info("发送审核拒绝通知成功: postId={}", post.getId());
            } catch (Exception e) {
                log.error("发送审核拒绝通知失败: {}", e.getMessage(), e);
            }
        } else {
            // 需要人工审核
            post.setStatus(PostConstants.STATUS_PENDING);
            postMapper.updateById(post);
            log.info("帖子需要人工审核: postId={}", post.getId());
        }
    }

    @Override
    public PostVO getPost(Long id) {
        Post post = postMapper.selectById(id);
        if (post == null) {
            throw new BusinessException("帖子不存在");
        }
        
        PostVO postVO = new PostVO();
        BeanUtils.copyProperties(post, postVO);
        
        // 从缓存获取用户信息
        Map<String, Object> userInfo = userCacheService.getUserInfo(post.getUserId());
        if (userInfo != null) {
            postVO.setAuthorName((String) userInfo.get("username"));
            postVO.setAuthorAvatar((String) userInfo.get("picture"));
        }
        
        // 设置分类名称
        postVO.setCategoryName(categoryMapper.selectNameById(post.getCategoryId()));
        
        // 设置标签列表
        List<Long> tagIds = postTagMapper.selectTagIdsByPostId(id);
        if (!tagIds.isEmpty()) {
            List<TagVO> tags = tagIds.stream()
                .map(tagId -> {
                    Tag tag = tagMapper.selectById(tagId);
                    TagVO tagVO = new TagVO();
                    BeanUtils.copyProperties(tag, tagVO);
                    return tagVO;
                })
                .collect(Collectors.toList());
            postVO.setTags(tags);
        }

        // 增加浏览量
        postMapper.incrementViews(id);
        
        return postVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public PostVO updatePost(Long id, PostDTO postDTO) {
        Post post = postMapper.selectById(id);
        if (post == null) {
            throw new BusinessException("帖子不存在");
        }
        
        // 验证分类ID
        if (postDTO.getCategoryId() != null && postDTO.getCategoryId() == 0) {
            throw new BusinessException("分类ID不能为0");
        }
        
        // 备份原始状态
        Integer originalStatus = post.getStatus();
        
        // 复制属性
        BeanUtils.copyProperties(postDTO, post);
        post.setUpdatedAt(LocalDateTime.now());
        
        // 如果当前用户不是管理员，并且内容或标题被修改，则状态设置为待审核
        // TODO: 判断是否为管理员，这里先假设所有更新都需要重新审核
        boolean contentChanged = postDTO.getContent() != null || postDTO.getTitle() != null;
        if (contentChanged && originalStatus == PostConstants.STATUS_PUBLISHED) { // 只有已发布的帖子修改后需要重新审核
            post.setStatus(PostConstants.STATUS_PENDING); // 设置为待审核
            log.info("帖子内容已修改，状态已更改为待审核: {}", id);
        }
        
        postMapper.updateById(post);
        
        // 更新标签
        if (postDTO.getTags() != null) {
            postTagMapper.deleteByPostId(id);
            handleTags(id, postDTO.getTags());
        }
        
        return getPost(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deletePost(Long id) {
        Post post = postMapper.selectById(id);
        if (post == null) {
            throw new BusinessException("帖子不存在");
        }
        
        postMapper.deleteById(id);
        postTagMapper.deleteByPostId(id);
    }

    @Override
    public String uploadImage(MultipartFile file) {
        log.info("开始上传图片, 原始文件名: {}, 大小: {}, 类型: {}", 
                file.getOriginalFilename(), file.getSize(), file.getContentType());
        
        // 检查文件类型
        String contentType = file.getContentType();
        List<String> allowedTypes = uploadConfig.getAllowedTypesList();
        log.info("允许的文件类型: {}", allowedTypes);
        
        if (!allowedTypes.contains(contentType)) {
            log.warn("不支持的文件类型: {}", contentType);
            throw new BusinessException("不支持的文件类型");
        }
        
        // 检查文件大小，设置默认大小限制为2MB
        long maxSize = uploadConfig.getMaxSize() != null ? uploadConfig.getMaxSize() : 2 * 1024 * 1024;
        log.info("文件大小限制: {}", maxSize);
        
        if (file.getSize() > maxSize) {
            log.warn("文件大小超出限制: {}", file.getSize());
            throw new BusinessException("文件大小超出限制");
        }
        
        // 生成文件名
        String originalFilename = file.getOriginalFilename();
        String extension = StringUtils.getFilenameExtension(originalFilename);
        String filename = UUID.randomUUID().toString() + "." + extension;
        log.info("生成的文件名: {}", filename);
        
        // 创建目录
        String uploadPath = uploadConfig.getPath() != null ? uploadConfig.getPath() : "E:/upload/forum/images/";
        log.info("上传目录: {}", uploadPath);
        
        File uploadDir = new File(uploadPath);
        if (!uploadDir.exists()) {
            log.info("上传目录不存在，创建目录: {}", uploadPath);
            boolean created = uploadDir.mkdirs();
            if (!created) {
                log.error("创建上传目录失败: {}", uploadPath);
                throw new BusinessException("创建上传目录失败");
            }
        }
        
        // 存储文件
        try {
            File destFile = new File(uploadDir, filename);
            log.info("目标文件路径: {}", destFile.getAbsolutePath());
            file.transferTo(destFile);
            String fileUrl = "/api/upload/images/" + filename;
            log.info("文件上传成功，返回URL: {}", fileUrl);
            return fileUrl;
        } catch (IOException e) {
            log.error("文件上传失败", e);
            throw new BusinessException("文件上传失败");
        }
    }

    @Override
    public List<CategoryVO> getCategories() {
        return categoryMapper.selectAll().stream()
            .map(category -> {
                CategoryVO categoryVO = new CategoryVO();
                BeanUtils.copyProperties(category, categoryVO);
                return categoryVO;
            })
            .collect(Collectors.toList());
    }

    @Override
    public List<TagVO> getTags() {
        return tagMapper.selectAll().stream()
            .map(tag -> {
                TagVO tagVO = new TagVO();
                BeanUtils.copyProperties(tag, tagVO);
                return tagVO;
            })
            .collect(Collectors.toList());
    }

    @Override
    public void incrementViews(Long id) {
        postMapper.incrementViews(id);
    }

    @Override
    public List<PostVO> getUserPosts(Long userId) {
        List<Post> posts = postMapper.selectByUserId(userId);
        return convertToPostVOList(posts);
    }

    @Override
    public List<PostVO> getCategoryPosts(Long categoryId) {
        List<Post> posts = postMapper.selectByCategoryId(categoryId);
        return convertToPostVOList(posts);
    }

    @Override
    public List<PostVO> getTagPosts(Long tagId) {
        List<Long> postIds = postTagMapper.selectPostIdsByTagId(tagId);
        if (postIds.isEmpty()) {
            return new ArrayList<>();
        }
        List<Post> posts = postMapper.selectByIds(postIds);
        return convertToPostVOList(posts);
    }

    /**
     * 处理标签
     */
    private void handleTags(Long postId, List<String> tagNames) {
        for (String tagName : tagNames) {
            // 查找或创建标签
            Tag tag = tagMapper.selectByName(tagName);
            if (tag == null) {
                tag = new Tag();
                tag.setName(tagName);
                tag.setUseCount(0);
                tag.setCreatedAt(LocalDateTime.now());
                tagMapper.insert(tag);
            }
            
            // 创建帖子-标签关联
            PostTag postTag = new PostTag();
            postTag.setPostId(postId);
            postTag.setTagId(tag.getId());
            postTag.setCreatedAt(LocalDateTime.now());
            postTagMapper.insert(postTag);
            
            // 更新标签使用次数
            tagMapper.incrementUseCount(tag.getId());
        }
    }

    /**
     * 转换为帖子视图对象列表
     */
    private List<PostVO> convertToPostVOList(List<Post> posts) {
        if (posts == null || posts.isEmpty()) {
            return new ArrayList<>();
        }
        
        return posts.stream()
            .map(post -> {
                PostVO postVO = new PostVO();
                BeanUtils.copyProperties(post, postVO);
                
                // 设置分类名称
                postVO.setCategoryName(categoryMapper.selectNameById(post.getCategoryId()));
                
                // 设置标签列表
                List<Long> tagIds = postTagMapper.selectTagIdsByPostId(post.getId());
                if (!tagIds.isEmpty()) {
                    List<TagVO> tags = tagIds.stream()
                        .map(tagId -> {
                            Tag tag = tagMapper.selectById(tagId);
                            TagVO tagVO = new TagVO();
                            BeanUtils.copyProperties(tag, tagVO);
                            return tagVO;
                        })
                        .collect(Collectors.toList());
                    postVO.setTags(tags);
                }
                
                return postVO;
            })
            .collect(Collectors.toList());
    }
} 